今天這篇文章要來介紹 Spring Boot 中對於快取的使用,會先簡單說明一下我遇到的問題,然後再進入實作解決問題
MyMomentum 是一個個人時間管理應用,使用者可以:
問題描述
有一次,我心滿意足的按下結束紀錄,跳出結束時間「已紀錄 30分鐘」,然後馬上點進統計頁面想看看自己達成目標的畫面。
結果畫面上空空如也,我剛剛結束的活動紀錄就像從來沒發生過,真是令人灰心啊。
其實最根本原因,是後端程式在搜尋時加上了@Cacheable,導致前端取回的資料,不是最新的資料,畫面上也就呈現了個寂寞,那麼
@Cacheable 的作用是什麼?
Spring Cache 提供了 @Cacheable 註解來實現方法的快取:
@Cacheable(value = "activityDistribution", key = "#activityId + '_' + #fromDate + '_' + #toDate + '_' + #grain")
public List<DistributionItem> getActivityDistribution(UUID activityId, Long userId, String fromDate, String toDate, String grain) {
// 複雜的數據庫查詢邏輯
// 只有第一次調用時會執行,後續直接返回快取結果
}
優點:
缺點:
簡單說明完後,讓我們回到問題本身
1. 快取配置分析
在 StatisticsService 中,我配置了三個快取:
@Service
public class StatisticsService {
@Cacheable(value = "activityDistribution", key = "#activityId + '_' + #fromDate + '_' + #toDate + '_' + #grain")
public List<DistributionItem> getActivityDistribution(...) { ... }
@Cacheable(value = "activityTrend", key = "#activityId + '_' + #fromDate + '_' + #toDate + '_' + #grain")
public List<TrendItem> getActivityTrend(...) { ... }
@Cacheable(value = "activityKPIs", key = "#userId + '_' + #activityId + '_' + #fromDate + '_' + #toDate")
public ActivityKPIs getActivityKPIs(...) { ... }
}
2. 數據流程
也就是說,我們在配置快取後並沒有對應的快取清除邏輯,導致資料庫更新後,API仍在回傳舊的資料
那麼要怎麼樣才能加上對應的快取清除邏輯,確保資料更新呢?
可以使用@CacheEvict,目前主要有兩種使用方式:
@CacheEvict(value = "activityDistribution", key ="#activityId + '_' + #fromDate + '_' + #toDate + '_' + #grain")
public RecordResponse createRecord(Long userId, RecordCreateRequest request) {
// 只清除特定活動的快取
}
快取怎麼新增的,就怎麼刪除快取。
優點:
缺點:
@CacheEvict(value = "activityDistribution", allEntries = true)
public RecordResponse createRecord(Long userId, RecordCreateRequest request) {
// 清除整個快取
}
優點:
缺點:
這邊我選方案二,因為:
以下開始實作:
1. 添加 import
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
2. 修改(這邊選一個範例呈現)
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class ActivityService {
/**
* Update an existing activity
*/
@Caching(evict = {
@CacheEvict(value = "activityDistribution", allEntries = true),
@CacheEvict(value = "activityTrend", allEntries = true),
@CacheEvict(value = "activityKPIs", allEntries = true)
})
public Activity updateActivity(UUID activityId, Long userId, String name, Integer goalTime, String color, String icon) {
// 原有邏輯保持不變
// ...
}
}
註解說明:
加上去之後測試一下,這次馬上能看到最新數據
當系統用戶增加時,可以考慮:
結語:
以上就是今天的內容,看來針對Mymomentum的內容還有很多需要調整的地方,後續首要之務就是來研究一下快取要怎麼處理,可能可以試著導入Redis。
感謝。